package business.customersubsystem;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import middleware.creditverifcation.CreditVerificationFacade;
import middleware.exceptions.DatabaseException;
import middleware.exceptions.MiddlewareException;
import middleware.externalinterfaces.CreditVerification;
import business.exceptions.BackendException;
import business.exceptions.BusinessException;
import business.exceptions.RuleException;
import business.externalinterfaces.Address;
import business.externalinterfaces.CartItem;
import business.externalinterfaces.CreditCard;
import business.externalinterfaces.CustomerProfile;
import business.externalinterfaces.CustomerSubsystem;
import business.externalinterfaces.DbClassAddressForTest;
import business.externalinterfaces.Order;
import business.externalinterfaces.OrderSubsystem;
import business.externalinterfaces.Rules;
import business.externalinterfaces.ShoppingCart;
import business.externalinterfaces.ShoppingCartSubsystem;
import business.ordersubsystem.OrderSubsystemFacade;
import business.shoppingcartsubsystem.ShoppingCartSubsystemFacade;
import business.util.OrderUtil;

public class CustomerSubsystemFacade implements CustomerSubsystem {

	ShoppingCartSubsystem shoppingCartSubsystem;
	OrderSubsystem orderSubsystem;
	List<Order> orderHistory;
	AddressImpl defaultShipAddress;
	AddressImpl defaultBillAddress;
	CreditCardImpl defaultPaymentInfo;
	CustomerProfileImpl customerProfile;
	boolean isAdmin = false;

	public void initializeCustomer(Integer id, int authorizationLevel)
			throws BackendException {
		isAdmin = (authorizationLevel >= 1);
		loadCustomerProfile(id);
		loadDefaultShipAddress();
		loadDefaultBillAddress();
		loadDefaultPaymentInfo();
		shoppingCartSubsystem = ShoppingCartSubsystemFacade.getInstance();
		shoppingCartSubsystem.setCustomerProfile(customerProfile);
		shoppingCartSubsystem.retrieveSavedCart();
		loadOrderData();

	}

	void loadCustomerProfile(Integer custId) throws BackendException {
		try {
			DbClassCustomerProfile dbclass = new DbClassCustomerProfile();
			dbclass.readCustomerProfile(custId);
			customerProfile = dbclass.getCustomerProfile();
		} catch (DatabaseException e) {
			throw new BackendException(e);
		}
	}

	void loadDefaultShipAddress() {// throws BackendException {

	}

	void loadDefaultBillAddress() {// throws BackendException {

	}

	void loadDefaultPaymentInfo() throws BackendException {
		// implement
	}

	public void refreshAfterSubmit() throws BackendException {
		loadOrderData();
	}

	void loadOrderData() throws BackendException {

		// retrieve the order history for the customer and store here
		// implement

	}

	public boolean isAdmin() {
		return isAdmin;
	}

	public static Address createAddress(String street, String city,
			String state, String zip) {
		return new AddressImpl(street, city, state, zip);
	}

	// /implementation of interface

	/**
	 * Return an (unmodifiable) copy of the order history.
	 */
	public List<Order> getOrderHistory() {
		return new ArrayList<Order>();
		// return Collections.unmodifiableList(orderHistory);
	}

	public void saveNewAddress(Address addr) throws BackendException {
		try {
			DbClassAddress dbClass = new DbClassAddress();
			dbClass.setAddress(addr);
			dbClass.saveAddress(customerProfile);
		} catch (DatabaseException e) {
			throw new BackendException(e);
		}
	}

	public CustomerProfile getCustomerProfile() {

		return customerProfile;
	}

	public Address getDefaultShippingAddress() {
		return defaultShipAddress;
	}

	public Address getDefaultBillingAddress() {
		return defaultBillAddress;
	}

	public void setShippingAddressInCart(Address addr) {
		shoppingCartSubsystem.setShippingAddress(addr);

	}

	public void setBillingAddressInCart(Address addr) {
		shoppingCartSubsystem.setBillingAddress(addr);

	}

	public CreditCard getDefaultPaymentInfo() {
		return defaultPaymentInfo;
	}

	public static CreditCard createCreditCard(String name, String num,
			String type, String expDate) {

		return new CreditCardImpl(name, expDate, num, type);
	}

	// for testing
	public CustomerProfile createCustomerProfile(Integer custid) {
		return new CustomerProfileImpl(custid, null, null);
	}

	public void setPaymentInfoInCart(CreditCard cc) {
		shoppingCartSubsystem.setPaymentInfo(cc);

	}

	// assumes array is in the form street,city,state,zip
	public static Address createAddress(String[] addressInfo) {

		return createAddress(addressInfo[0], addressInfo[1], addressInfo[2],
				addressInfo[3]);
	}

	public Address runAddressRules(Address addr) throws RuleException,
			BusinessException {

		RulesAddress transferObject = new RulesAddress(addr);
		transferObject.runRules();

		// updates are in the form of a List; 0th object is the necessary
		// Address
		AddressImpl update = (AddressImpl) transferObject.getUpdates().get(0);
		return update;
	}

	public ShoppingCartSubsystem getShoppingCart() {
		return shoppingCartSubsystem;
	}

	/**
	 * Customer Subsystem is responsible for obtaining all the data needed by
	 * Credit Verif system -- it does not (and should not) rely on the
	 * controller for this data.
	 */
	@Override
	public void checkCreditCard() throws BusinessException {
		List<CartItem> items = ShoppingCartSubsystemFacade.getInstance()
				.getLiveCartItems();
		ShoppingCart theCart = ShoppingCartSubsystemFacade.getInstance()
				.getLiveCart();
		Address billAddr = theCart.getBillingAddress();
		CreditCard cc = theCart.getPaymentInfo();
		String amount = OrderUtil.quickComputeTotalPrice(items);
		CreditVerification creditVerif = new CreditVerificationFacade();
		try {
			creditVerif.checkCreditCard(customerProfile, billAddr, cc,
					new Double(amount));
		} catch (MiddlewareException e) {
			throw new BusinessException(e);
		}
	}

	@Override
	public List<Address> getAllAddresses() throws BackendException {
		// TODO Auto-generated method stub

		ArrayList<Address> address = new ArrayList<Address>();
		
		Address e= new  AddressImpl("Berlington", "Fairfield", "IA", "53557");
		address.add(e);
		return address;
	}

	@Override
	public void submitOrder() throws BackendException {
		// TODO Auto-generated method stub

	}

	@Override
	public void saveShoppingCart() throws BackendException {
		// TODO Auto-generated method stub

	}

	@Override
	public void runPaymentRules(Address addr, CreditCard cc)
			throws RuleException, BusinessException {
		// TODO Auto-generated method stub

	}

	@Override
	public DbClassAddressForTest getGenericDbClassAddress() {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public CustomerProfile getGenericCustomerProfile() {
		// TODO Auto-generated method stub
		return null;
	}

}
